/**
 * 
 */
package com.magnusart.scrumify.dao;

import static org.junit.Assert.*;
import static org.junit.Assume.*;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.magnusart.scrumify.dao.ProjectDAO3;
import com.magnusart.scrumppm.model.Project;
import com.magnusart.scrumppm.model.ProjectBuilder;

/**
 * Tests the actions used by Project DAO using HsqlDb
 * 
 * @author Magnus Andersson
 * 
 */
public class ProjectDAOSpecification_HsqlDB3
{

	private ProjectDAO3 project;

	private DBTestUtil.SeamedHsqlDbDAOFactory factory;

	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {

		DBTestUtil.setUpTempDatabase();
		
		factory = new DBTestUtil.SeamedHsqlDbDAOFactory();

		// Use our seamed instance with a special sql connection.
		project = factory.getProjectDAO3();		
		
	}


	/**
	 * @throws java.lang.Exception
	 */
	@After
	public void tearDown() throws Exception {
		DBTestUtil.closeConn();
	}


	/**
	 * Adds two projects to the database and then retrieves them from the DAO
	 * @throws Exception
	 */
	@Test
	public void shouldInsertProjectAndListIt() throws Exception {
		// Get ProjectDAO3
		String[] projectName = { "TestProject", "Test2" };
		String[] projectDesc = { "A project description...", "Second project." };

		Project added = null;
		ProjectBuilder builder = new ProjectBuilder();
		for( int i = 0; i < projectName.length; i++ ) {
			builder.setName( projectName[i] );
			builder.setDescription( projectDesc[i] );
			
			added = project.addNewProject( new Project( builder ) );
			assertTrue( added instanceof Project );
		}

		List<Project> projects = project.getAllProjects();

		for( int i = 0; i < projectName.length; i++ ) {
			builder.setName( projectName[i] );
			builder.setDescription( projectDesc[i] );
			
			assertTrue( "Could not find a project by the name " + projectName[i] + " in the collection", find( projects,  new Project( builder ) ) );
			
			assertEquals( "Could not find the project description for "
					+ projectName[i] + ".", projects.get( i ).getDescription(), projectDesc[i] );

		}
	}

	@Test
	public void shouldNotAllowProjectNameDuplicates() throws Exception {
		String projectName = "TestProject";
		String projectDesc = "Description...";
		String projectName2 = "TestProject2";
		
		ProjectBuilder builder = new ProjectBuilder();
		builder.setName( projectName );
		builder.setDescription( projectDesc );
		
		Project added = project.addNewProject( new Project( builder) );
		Project notadded = project.addNewProject( new Project( builder ) );
		builder.setName( projectName2 );
		Project differentdesc = project.addNewProject( new Project( builder ) );
		
		assertTrue( "The original project should have been added!", added instanceof Project );
		assertFalse( "The duplicate project should not have been added!", notadded instanceof Project );
		assertTrue( "The description should allow duplicates!", differentdesc instanceof Project );
	}
	
	@Test
	public void shouldListOnlyUnfinishedProjects() throws Exception {
		String projectName = "Project";
		String description = "Description";
		ProjectBuilder builder = new ProjectBuilder();
		
		int n = 5;
		ArrayList<Project> projs = new ArrayList<Project>();
		boolean added = false;
		Project proj = null;
		
		for( int i = 0; i < n; i++ ) {
			builder.setName( projectName + i );
			builder.setDescription( description + i );
			added = projs.add( project.addNewProject( new Project( builder ) ) );
			assertTrue( added );
		}
		
		// Close two projects
		proj = project.closeProject( projs.get( 1 ) );
		assertTrue( proj instanceof Project );
		
		proj = project.closeProject( projs.get( 2 ) );
		assertTrue( proj instanceof Project );
		
		List<Project> projects = project.getOpenProjects();
		
		assertNotNull( projects );
		
		builder.setName( projectName + 0 );
		assertTrue( "Project0 is supposed to be open!", find( projects,  new Project( builder ) ) );
		
		builder.setName( projectName + 1 );
		assertFalse( "Project1 is NOT supposed to be open!", find( projects,  new Project( builder ) ));
		
		builder.setName( projectName + 2 );
		assertFalse( "Project2 is NOT supposed to be open!", find( projects,  new Project( builder ) ));
		
		builder.setName( projectName + 3 );
		assertTrue( "Project3 is supposed to be open!", find( projects,  new Project( builder ) ));
	
		builder.setName( projectName + 4 );
		assertTrue( "Project4 is supposed to be open!", find( projects,  new Project( builder ) ) );
	
		
		projects = project.getClosedProjects();
		
		proj = project.openProject( projs.get( 2 ) );
		
		assertTrue( proj instanceof Project );
		
		projects = project.getClosedProjects();
		
		builder.setName( projectName + 2 );		
		assertFalse( "Project2 is supposed to be open now!", find( projects,  new Project( builder ) ) );
		builder.setName(  projectName + 1 );
		assertTrue( "Project1 is still supposed to be closed", find( projects,  new Project( builder ) ));
	}
	
	@Test
	public void shouldDeleteAddedProject() throws Exception {
		String projectName = "Project";
		String description = "Description";
	
		ProjectBuilder builder = new ProjectBuilder();
		builder.setName( projectName );
		builder.setDescription( description );
		
		Project proj = project.addNewProject( new Project( builder ) );
		assumeTrue( proj instanceof Project );
		
		List<Project> projects = project.getAllProjects();
		assertTrue( find( projects,  proj ) );
		
		project.deleteProject( proj );
		
		projects = project.getAllProjects();
		assertFalse( find( projects,  proj ) );
		
		projects = project.getAllProjects();
		builder.setName( "ScrumPPM" );
		builder.setDescription( "desc" );
		Project proj2 = new Project( builder );
		assertTrue( find( projects,  proj2 ) );
		
		project.deleteProject( proj2 );
		
		projects = project.getAllProjects();
		assertFalse( find( projects,  proj2 ) );
	}
	
	@Test
	public void databaseIgnoresCase() throws Exception {
		ProjectBuilder builder = new ProjectBuilder();
		builder.setName( "Test" );
		builder.setDescription( "test" );
		Project added = project.addNewProject( new Project( builder ) );
		assertTrue( added instanceof Project );
		
		builder.setName( "TeSt" );
		builder.setDescription( "test 2" );
		added = project.addNewProject(  new Project(  builder ) );
		assertFalse( added instanceof Project );
	}
	
	private boolean find( List<Project> projs, Project p ) {
		return Collections.binarySearch( projs,  p ) >= 0;
	}
}
